﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Media.Media3D;
using C4F.VistaP2P.WPF;

namespace ComplexP2PSample
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {

        //In order to obtain the desired 3d button effect, the buttons are mapped to a plane Mesh in a viewport element,
        //The function OnButtonViewPortMouseDown does a raycast into the viewport in order to see which panel was hit.
        //the appropriate control is then referenced and a button press event is sent to it.
        private System.Collections.ArrayList m3DObject;
        private System.Collections.ArrayList m2DControl;
        private GeometryModel3D hit; //used in OnButtonViewPortMouseDown to keep track of which panels were hit.
        GeometryModel3D lastHit; //used in OnButtonViewPortMouseDown to keep track of which panels were hit.

        public Window1()
        {
            InitializeComponent();

            this.UpdateLayout();
            ComponentCanvas.Visibility = Visibility.Hidden;
            //////////////////////////////////////////////////////////////////////
            //Set up the 3d buttons.
            //////////////////////////////////////////////////////////////////////
            m2DControl = new System.Collections.ArrayList();
            m3DObject = new System.Collections.ArrayList();

            Rotation3D r3d = new AxisAngleRotation3D(new Vector3D(0, 1, 0), -15);
            Add(this.mSendPicture, mSendPicture.Width, mSendPicture.Height, new Point3D(-15, 0, -14), new RotateTransform3D(r3d, new Point3D(12, 0, 0)));

            r3d = new AxisAngleRotation3D(new Vector3D(0, 1, 0), -25);
            Add(mSendAudio, mSendAudio.Width, mSendAudio.Height, new Point3D(-13, 1.5, -14), new RotateTransform3D(r3d, new Point3D(12, 0, 0)));

            r3d = new AxisAngleRotation3D(new Vector3D(0, 1, 0), -40);
            Add(mSendVideo, mSendVideo.Width, mSendVideo.Height, new Point3D(-13, 3, -13), new RotateTransform3D(r3d, new Point3D(12, 0, 0)));

            r3d = new AxisAngleRotation3D(new Vector3D(0, 1, 0), -62);
            Add(mSendFile, mSendFile.Width, mSendFile.Height, new Point3D(-13, 4.5, -10), new RotateTransform3D(r3d, new Point3D(12, 0, 0)));

            pictureControl1.PictureReceived += new EventHandler<C4F.VistaP2P.Common.PictureChangedEventArgs>(_PictureReceived);

            this.mediaVideoControl.MediaElement = mMediaVideoViewPort.MediaElement;
            mediaVideoControl.StartPlayChanged += new EventHandler(_StartVideoPlayChanged);

            mediaAudioControl.MediaElement = mMediaAudioViewPort.MediaElement;
            mediaAudioControl.StartPlayChanged += new EventHandler(_StartAudioPlayChanged);
        }

        private void _StartVideoPlayChanged(object sender, EventArgs e)
        {            
            mMediaVideoViewPort.Visibility = Visibility.Visible;
            mMediaAudioViewPort.Visibility = Visibility.Hidden;            
            mImage.Visibility = Visibility.Hidden;
        }

        private void _StartAudioPlayChanged(object sender, EventArgs e)
        {
            mMediaVideoViewPort.Visibility = Visibility.Hidden;
            mMediaAudioViewPort.Visibility = Visibility.Visible;
            mImage.Visibility = Visibility.Hidden;
        }

        private void _PictureReceived(object sender, C4F.VistaP2P.Common.PictureChangedEventArgs e)
        {
            mMediaAudioViewPort.Visibility = Visibility.Hidden;            
            mMediaVideoViewPort.Visibility = Visibility.Hidden;
            mImage.Visibility = Visibility.Visible;
        }

        /// <summary>
        ///  Given a normal 2d control, the width, size, it maps the controls visual display to the panel.
        ///  The panel is then placed in the viewport. pos is the position in the viewport and trans is the orientation.
        /// </summary>
        /// <param name="l">The 2d control</param>
        /// <param name="width">the width of the control</param>
        /// <param name="height">the height of the control</param>
        /// <param name="pos">the position in the viewport</param>
        /// <param name="trans">the orientation</param>
        public void Add(Visual l, double width, double height, Point3D pos, Transform3D trans)
        {

            //Store the Visual of the control in the ArrayList, we'll need it later to send it messages
            m2DControl.Add(l);


            Plane p = new Plane();
            ModelVisual3D model = new ModelVisual3D();

            double scale = .1;
            p.UpperLeft = new Point3D(pos.X + scale * (-width / 2), pos.Y + scale * (-height / 2), pos.Z);
            p.LowerRight = new Point3D(pos.X + scale * width / 2, pos.Y + scale * height / 2, pos.Z);

            //Create the model on which to draw the control's Visual
            ModelVisual3D modelVisual3d = new ModelVisual3D();
            Model3DGroup modelGroup = new Model3DGroup();
            GeometryModel3D model3d = new GeometryModel3D(p.Mesh, new DiffuseMaterial(new SolidColorBrush(Colors.Green)));//new GeometryModel3D();

            //perform the transform on the model
            model3d.Transform = trans;

            //Create the material with the texture of the Control and use it on the model
            DiffuseMaterial visualMaterial = new DiffuseMaterial(new VisualBrush(l));
            model3d.Material = visualMaterial;
            modelGroup.Children.Add(model3d);
            modelVisual3d.Content = modelGroup;

            //Store the model in the ArayList, we'll need it for hittesting
            m3DObject.Add(model3d);

            //Add the new plane to the ViewPort, so that we can see it
            buttonViewport.Children.Add(modelVisual3d);
        }



        /// <summary>
        /// When someone clicks on the viewport area, figure out if they hit one of the panels. If so then
        /// look up which 2d Control was mapped onto that panel.  Then raise the event with the 2d control.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void OnButtonViewPortMouseDown(object sender, System.Windows.RoutedEventArgs e)
        {
            System.Windows.Point mouseposition = ((MouseButtonEventArgs)e).GetPosition(buttonViewport);
            Point3D testpoint3D = new Point3D(mouseposition.X, mouseposition.Y, 0);
            Vector3D testdirection = new Vector3D(mouseposition.X, mouseposition.Y, 10);
            PointHitTestParameters pointparams = new PointHitTestParameters(mouseposition);
            RayHitTestParameters rayparams = new RayHitTestParameters(testpoint3D, testdirection);
            //test for a result in the Viewport3D   
            hit = null;
            VisualTreeHelper.HitTest(buttonViewport, null, HTResult, pointparams);
            for (int i = 0; i < m3DObject.Count; i++)
                if (m3DObject[i] == hit)
                {
                    hit = null;
                    Button hitButton = (Button)m2DControl[i];
                    hitButton.RaiseEvent(e);
                }
        }

        /// <summary>
        /// This is used by OnButtonViewPortMouseDown to parse the results of the raycast on the panel.
        /// </summary>
        /// <param name="rawresult"></param>
        /// <returns></returns>
        public HitTestResultBehavior HTResult(System.Windows.Media.HitTestResult rawresult)
        {
            RayHitTestResult rayResult = rawresult as RayHitTestResult;
            //if the mouse was clicked on a panel, figure out which one.
            if (rayResult != null)
            {
                DiffuseMaterial darkSide = new DiffuseMaterial(new SolidColorBrush(System.Windows.Media.Colors.Red));
                bool gasit = false;
                for (int i = 0; i < m3DObject.Count; i++)
                    if ((GeometryModel3D)m3DObject[i] == rayResult.ModelHit)
                    {
                        hit = (GeometryModel3D)rayResult.ModelHit;
                        gasit = true;
                    }
                if (!gasit) { hit = null; }
            }

            return HitTestResultBehavior.Stop;
        }



        bool leaving;
        Button hitButton;
        protected void OnButtonViewPortMouseLeave(object sender, System.Windows.RoutedEventArgs e)
        {



        }

        protected void hitButton_MouseEnter(object sender, System.Windows.RoutedEventArgs e)
        {
            //bool jkl = this.buttonJoinLeaveNetwork.IsMouseOver;
        }

        protected void OnButtonViewPortMouseEnter(object sender, System.Windows.RoutedEventArgs e)
        {
            System.Windows.Point mouseposition = ((MouseEventArgs)e).GetPosition(buttonViewport);
            Point3D testpoint3D = new Point3D(mouseposition.X, mouseposition.Y, 0);
            Vector3D testdirection = new Vector3D(mouseposition.X, mouseposition.Y, 10);
            PointHitTestParameters pointparams = new PointHitTestParameters(mouseposition);
            RayHitTestParameters rayparams = new RayHitTestParameters(testpoint3D, testdirection);
            //test for a result in the Viewport3D   
            hit = null;

            VisualTreeHelper.HitTest(buttonViewport, null, HTResult, pointparams);
            //if we hit a real panel for the first time.
            if ((hit != lastHit) && (hit != null))
            {
                if (leaving)
                {
                    leaving = false;
                    return;
                }
                for (int i = 0; i < m3DObject.Count; i++)
                {
                    if (m3DObject[i] == hit)
                    {
                        hit = null;
                        hitButton = (Button)m2DControl[i];

                        // hitButton.Focus();

                        hitButton.RaiseEvent(e);
                    }
                }

                lastHit = hit;
            }
        }

        /// <summary>
        /// We need to notify the button on mouse moves as well, to make the UI act appropriately.
        /// this is just another mapping from the viewport space to the 2d controls.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void OnButtonViewPortMouseMove(object sender, System.Windows.RoutedEventArgs e)
        {


            //if (lastHit != null && hit == null)
            //{
            //    //well they must have moved off the panel..free the mouse from the control.
            //    for (int i = 0; i < m3DObject.Count; i++)
            //    {
            //        if (m3DObject[i] == lastHit)
            //        {
            //            Button hitButton = (Button)m2DControl[i];
            //            hitButton.ReleaseMouseCapture();
            //            lastHit = null;
            //        }
            //    }
            //}
        }

        private void mImage_ImageFailed(object sender, ExceptionRoutedEventArgs e)
        {

        }
        
            

    }
}
